#include "StdAfx.h"
#include "InputLanguage.h"

CInputLanguage::CInputLanguage(HWND hWnd)
{
    m_hWnd = hWnd;
    m_hImc = NULL;
}

CInputLanguage::~CInputLanguage(void)
{
}

void CInputLanguage::SetImeOpenStatus(BOOL bOpenStatus)
{
    HIMC hImc = ::ImmGetContext(m_hWnd);
    if (hImc != NULL)
    {
        ::ImmSetOpenStatus(hImc, bOpenStatus);
        ::ImmReleaseContext(m_hWnd, hImc);
    }
}

BOOL CInputLanguage::IsImeOpen()
{
    HIMC hImc = ::ImmGetContext(m_hWnd);
    BOOL isOpen = FALSE;
    if (hImc != NULL)
    {
        isOpen = ::ImmGetOpenStatus(hImc);
        ::ImmReleaseContext(m_hWnd, hImc);
    }
    return isOpen;
}

void CInputLanguage::DisableIme()
{
    SetImeOpenStatus(FALSE);
    ::ImmAssociateContext(m_hWnd, NULL);
}

void CInputLanguage::EnableIme()
{
    HIMC hImc = ::ImmGetContext(m_hWnd);
    if (hImc == NULL)
    {
        if (m_hImc == NULL)
        {
            m_hImc = ::ImmCreateContext();
            if (m_hImc != NULL)
            {
                ::ImmAssociateContext(m_hWnd, m_hImc);
            }
        }
        else
        {
            ::ImmAssociateContext(m_hWnd, m_hImc);
        }
    }
    else
    {
        ::ImmReleaseContext(m_hWnd, hImc);
    }
    if (!IsImeOpen())
    {
        SetImeOpenStatus(TRUE);
    }
}

InputLanguage CInputLanguage::GetCurrentInputLanguage()
{
    HKL hKL = ::GetKeyboardLayout(0);
    switch (((INT_PTR)hKL) & 0x0000FFFF)
    {
    case 0x411:
        return LANGUAGE_JAPANESE;   // "00000411"   "E0010411"  "E0200411"

    case 0x412:
    case 0x812:
        return LANGUAGE_KOREAN;     // "00000412"   "E0010412"

    case 0x804:
    case 0x404:
    case 0x1004:
    case 0x1404:
    case 0xc04:
        return LANGUAGE_CHINESE;    // "E0010804"   "E0020804"  "E0200804"
    }
    return LANGUAGE_UNKNOWN;
}

BOOL CInputLanguage::CheckLanguage(HKL hKL, InputLanguage lang)
{
    switch (((INT_PTR)hKL) & 0x0000FFFF)
    {
    case 0x411:
        return (LANGUAGE_JAPANESE == lang);

    case 0x412:
    case 0x812:
        return (LANGUAGE_KOREAN == lang);

    case 0x804:
    case 0x404:
    case 0x1004:
    case 0x1404:
    case 0xc04:
        return (LANGUAGE_CHINESE == lang);
    }
    return FALSE;
}

void CInputLanguage::ActiveInputLanguage(InputLanguage lang)
{
    HKL hKLArray[24];
    UINT uCount = GetKeyboardLayoutList(24, hKLArray);
    switch(lang)
    {
    case LANGUAGE_JAPANESE:
        if(LANGUAGE_JAPANESE != GetCurrentInputLanguage())
        {
            for(UINT uIndex = 0; uIndex < uCount; uIndex++)
            {
                if(CheckLanguage(hKLArray[uIndex], LANGUAGE_JAPANESE))
                {
                    //HKL hKeyboardLayout = LoadKeyboardLayout(L"E0010411", KLF_ACTIVATE);
                    ActivateKeyboardLayout(hKLArray[uIndex], KLF_SETFORPROCESS);
                    break;
                }
            }
        }
        break;
    case LANGUAGE_KOREAN:
        if(LANGUAGE_KOREAN != GetCurrentInputLanguage())
        {
            for(UINT uIndex = 0; uIndex < uCount; uIndex++)
            {
                if(CheckLanguage(hKLArray[uIndex], LANGUAGE_KOREAN))
                {
                    ActivateKeyboardLayout(hKLArray[uIndex], KLF_SETFORPROCESS);
                    break;
                }
            }
        }
        break;
    case LANGUAGE_CHINESE:
        if(LANGUAGE_CHINESE != GetCurrentInputLanguage())
        {
            for(UINT uIndex = 0; uIndex < uCount; uIndex++)
            {
                if(CheckLanguage(hKLArray[uIndex], LANGUAGE_CHINESE))
                {
                    ActivateKeyboardLayout(hKLArray[uIndex], KLF_SETFORPROCESS);
                    break;
                }
            }
        }
        break;
    default:
        break;
    }
}

BOOL CInputLanguage::GetImeConversionBits(int nImeMode, int& nSetBits, int& nClearBits)
{
    nSetBits = 0;
    nClearBits = 0;
    switch(nImeMode)
    {
    case ImeMode::Hiragana:     // 9.2
        nSetBits = 9;
        nClearBits = 2;
        break;
    case ImeMode::Katakana:     // 11.0
        nSetBits = 11;
        nClearBits = 0;
        break;
    case ImeMode::KatakanaHalf: // 3.8
        nSetBits = 3;
        nClearBits = 8;
        break;
    case ImeMode::AlphaFull:    // 8.3
        nSetBits = 8;
        nClearBits = 3;
        break;
    case ImeMode::Alpha:        // 0.11
        nSetBits = 0;
        nClearBits = 11;
        break;
    case ImeMode::HangulFull:   // 9.0
        nSetBits = 9;
        nClearBits = 0;
        break;
    case ImeMode::Hangul:       // 1.8
        nSetBits = 1;
        nClearBits = 8;
        break;
    case ImeMode::OnHalf:       // 1.10
        nSetBits = 1;
        nClearBits = 10;
        break;
    default:                    // 0.0
        nSetBits = 0;
        nClearBits = 0;
        break;
    }
    if((nSetBits == 0) && (nClearBits == 0))
    {
        return FALSE;
    }
    return TRUE;
}

void CInputLanguage::SetImeStatus(int nImeMode)
{
    if ((nImeMode == ImeMode::Inherit) 
        || (nImeMode == ImeMode::NoControl)
        || (LANGUAGE_UNKNOWN == GetCurrentInputLanguage())
        )
    {
        return;
    }
    if (nImeMode == ImeMode::Disable)
    {
        DisableIme();
    }
    else
    {
        EnableIme();
    }
    BOOL bNeedCheckInputLanguage = FALSE;
    switch (nImeMode)
    {
    case ImeMode::NoControl:
    case ImeMode::Disable:
        return;
    case ImeMode::On:
        nImeMode = ImeMode::Hiragana;
        break;
    case ImeMode::Off:
        if (LANGUAGE_JAPANESE == GetCurrentInputLanguage())
        {
            break;
        }
        nImeMode = ImeMode::Alpha;
        break;
    case ImeMode::Close:
        bNeedCheckInputLanguage = TRUE;
        break;
    default:
        break;
    }
    SetImeOpenStatus(TRUE);
    if(bNeedCheckInputLanguage)
    {
        if (LANGUAGE_KOREAN == GetCurrentInputLanguage())
        {
            nImeMode = ImeMode::Alpha;
        }
        else
        {
            SetImeOpenStatus(FALSE);
            return;
        }
    }
    int nSetBits = 0;
    int nClearBits = 0;
    DWORD dwConversion = 0;
    DWORD dwSentence = 0;
    if (GetImeConversionBits(nImeMode, nSetBits, nClearBits))
    {
        HIMC hImc = ::ImmGetContext(m_hWnd);
        if(hImc != NULL)
        {
            ::ImmGetConversionStatus(hImc, &dwConversion, &dwSentence);
            dwConversion |= nSetBits;
            dwConversion &= ~nClearBits;
            ::ImmSetConversionStatus(hImc, dwConversion, dwSentence);
            ::ImmReleaseContext(m_hWnd, hImc);
            hImc = NULL;
        }
    }
}

